#ifndef HEX_ENCODE_H_
#define HEX_ENCODE_H_

#include <iostream>
#include <fstream>
#include <stdint.h>
#include <iomanip>
#include <sstream>
#include <string>

class HexEncode {
private:
	const char* file_path;

	//Convierte un digito hexadecimal a binario
	unsigned int HexaDigitToBinary(char c) {
		unsigned int digit = 80;
		if ((c >= '0') && (c <= '9')) {

			digit = c - '0';
		}
		if ((c >= 'A') && (c <= 'F')) {

			digit = c - 'A' + 10;
		}
		return digit;
	}

	//Convierte un byte hexadecimal a binario
	int HexByteToBinary(char c1, char c2) {
		return HexaDigitToBinary(c1) * 16 + HexaDigitToBinary(c2);
	}
public:
	HexEncode(const char* path) {
		this->file_path = path;
	}

	~HexEncode() {
	}

	//Levanta el contenido de un archivo en un string
	static string FileToString(const char* path) {
		ifstream ifs(path, ios::in | ios::binary);
		string buffer;
		int c = 0;
		while (ifs.good()) {
			c = ifs.get();
			if (ifs.good())
				buffer.push_back(c);

		}
		if (ifs.is_open()) {
			ifs.close();
		}
		return buffer;
	}

	//Codifica a hexa el archivo binario del path
	string Encode() {
		string buffer = FileToString(this->file_path);
		ostringstream ret;
		bool upper_case = true;
		//Conversion a hexadecimal
		for (string::size_type i = 0; i < buffer.length(); ++i) {
			int z = buffer[i] & 0xff;
			ret << std::hex << std::setfill('0') << std::setw(2)
					<< (upper_case ? std::uppercase : std::nouppercase) << z;
		}

		return ret.str();
	}

	//Decodifica de hexa a bin y guarda en el path, el hexadecimal del string
	void Desencode(string* hexa_file) {
		FILE* fp = fopen(this->file_path, "wb");

		if (hexa_file->size() > 0) {
			for (unsigned int i = 0; i < hexa_file->size() - 1; i = i + 2) {
				char c1, c2;
				c1 = hexa_file->at(i);
				c2 = hexa_file->at(i + 1);
				char byte = HexByteToBinary(c1, c2);

				fputc(byte, fp);

			}
		}

		fclose(fp);
	}
};

#endif /* HEX_ENCODE_H_ */
